// decltype 语法解析
// decltype 是 C++11 引入的一个关键字，用于获取表达式的类型。

// 基本语法
decltype(expression)
// decltype 返回 expression 的精确类型，包括 cv 限定符（const/volatile）和引用。

// 工作规则
// 1.如果表达式是一个标识符（变量名）或类成员访问：
//      decltype 返回该标识符或成员的声明类型
// 2.如果表达式是函数调用：
//      decltype 返回函数的返回类型
// 3.如果表达式是一个左值：
//      decltype 返回左值引用类型（T&）
// 4.其他情况：
//      decltype 返回表达式的类型

decltype(std::declval<C>().size(), std::true_type{})

// 这里使用了逗号表达式，其类型是最后一个子表达式的类型。因此：
// 如果 C 有 size() 方法，整个表达式的类型是 std::true_type
// 如果 C 没有 size() 方法，std::declval<C>().size() 无效，导致替换失败\

// decltype 示例
int i = 42;
const int &ri = i;
int arr[10];
int *pi = &i;

// 基本类型
decltype(i) x1;      // int
decltype(ri) x2 = i; // const int&
decltype(pi) x3;     // int*

// 表达式
decltype(i + 1) x4;      // int
decltype(*pi) x5 = i;    // int& (因为 *pi 是左值)
decltype(arr[0]) x6 = i; // int& (数组元素访问是左值)
decltype((i)) x7 = i;    // int& (括号表达式是左值)

// 函数调用
decltype(std::string().size()) x8; // size_t 或 std::size_t

// decltype 与逗号表达式
// 在 decltype(expr1, expr2, ..., exprN) 中：
// 1.不是"条件和返回类型"的关系：
//      这里使用的是 C++ 的逗号运算符，它会依次求值所有表达式，但只返回最后一个表达式的值和类型
//      所有表达式都会参与类型检查，如果任何一个表达式无效，整个 decltype 表达式就会失败

// 更准确的理解方式
// 前面的表达式：用于检测条件（是否可以编译）
// 最后的表达式：决定 decltype 的结果类型
// 这不是"条件和返回类型"的关系，而是"检测和类型选择"的关系。所有表达式都必须有效才能得到最后一个表达式的类型。

// 实际例子
// 检测是否可加
template <typename T, typename U>
auto is_addable(int) -> decltype(std::declval<T>() + std::declval<U>(), std::true_type{});

// 检测是否有size方法
template <typename T>
auto has_size(int) -> decltype(std::declval<T>().size(), std::true_type{});

// 在这些例子中：
// 前面的表达式（std::declval<T>() + std::declval<U>()或std::declval<T>().size()）用于检测条件
// 最后的表达式（std::true_type{}）决定返回类型
// 如果检测失败，整个函数模板实例化失败，触发 SFINAE

// 所以，虽然您的记忆方式在实践中可能有帮助，但理解底层机制会更有助于掌握这种技术。